package com.platform.comm.util;

import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Date;
import java.util.Objects;

/**
 * Utils of date/time
 */
public abstract class DateTimeUtil {
    public static final String STD_LONG_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String STD_DATE_FMT_PATTERN = "yyyy-MM-dd";
    public static final String STD_MONTH_FMT_PATTERN = "yyyy-MM";

    private static final DateTimeFormatter STD_LONG_TIME_FMT = DateTimeFormatter.ofPattern(STD_LONG_TIME_PATTERN);

    private static final DateTimeFormatter STD_DATE_FMT = DateTimeFormatter.ofPattern(STD_DATE_FMT_PATTERN);

    private static final DateTimeFormatter STD_MONTH_FMT = DateTimeFormatter.ofPattern(STD_MONTH_FMT_PATTERN);

    private static final DateTimeFormatter COMPACT_LONG_TIME_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    private static final DateTimeFormatter WITHOUT_YEAR_COMPACT_FMT = DateTimeFormatter.ofPattern("MMddHHmmss");

    private static final DateTimeFormatter CN_STYLE_DATE_FMT = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

    /**
     * 将时间转换为标准的 <b>年-月-日 时:分:秒</b> 格式
     */
    public static String toStdLongTimeStr(LocalDateTime time) {
        return time == null ? null : time.format(STD_LONG_TIME_FMT);
    }

    /**
     * 将 <b>年-月-日 时:分:秒</b> 格式字符串解析为{@link LocalDateTime}实例
     */
    public static LocalDateTime parseStdLongTimeStr(String text) {
        return StringUtils.isBlank(text) ? null : LocalDateTime.parse(text, STD_LONG_TIME_FMT);
    }

    /**
     * 根据时间格式转换时间
     * @param text      原始数据
     * @param pattern   时间格式
     * @return  LocalDateTime
     */
    public static LocalDateTime parseStdLongTimeStr(String text, String pattern) {
        return LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 将时间转换为标准的 <b>年-月-日</b> 日期格式
     */
    public static String toStdDateStr(LocalDateTime time) {
        return time == null ? null : time.format(STD_DATE_FMT);
    }

    /**
     * 将 <b>年-月-日</b> 格式字符串解析为{@link LocalDateTime}实例
     */
    public static LocalDateTime parseStdDateTimeStr(String text) {
        LocalDate localDate = toLocalDate(text);
        ZoneId zone = ZoneId.systemDefault();
        Objects.requireNonNull(localDate, "localDate");
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return LocalDateTime.ofInstant(instant,zone);
    }

    /**
     * 将当前时间转换为紧凑格式的字符串
     *
     * @see #toCompatLongStr(LocalDateTime)
     */
    public static String toCompatLongStr() {
        return toCompatLongStr(LocalDateTime.now());
    }

    /**
     * 将时间对象转换为紧凑格式(<code>yyyyMMddHHmmss</code>)的字符串
     */
    public static String toCompatLongStr(LocalDateTime time) {
        return time == null ? null : COMPACT_LONG_TIME_FMT.format(time);
    }

    /**
     * 将当前时间转换为紧凑格式(<code>MMddHHmmss</code>)，不包括年
     */
    public static String toCompatStrWithoutYear() {
        return WITHOUT_YEAR_COMPACT_FMT.format(LocalDateTime.now());
    }

    /**
     * 将日期转换为<code>yyyy年MM月dd日</code>格式
     */
    public static String toCnDateString(LocalDate date) {
        return CN_STYLE_DATE_FMT.format(date);
    }

    /**
     * 转换字符串 为 LocalDate
     * @param date 格式为 yyyy-mm-dd
     * @return LocalDate
     */
    public static LocalDate toLocalDate(String date){
        return LocalDate.parse(date, STD_DATE_FMT);
    }

    /**
     * 将日期转换为<code>yyyy-MM-dd</code>格式
     */
    public static String toStdDateStr(LocalDate date) {
        return STD_DATE_FMT.format(date);
    }

    /**
     * 将日期转换为<code>yyyy-MM</code>格式
     */
    public static String toStdMonthStr(LocalDate date) {
        return STD_MONTH_FMT.format(date);
    }

    /**
     * 计算时间段<b>时分秒</b> 格式
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static String toDurationTimeStr(LocalDateTime startTime, LocalDateTime endTime) {
        if (Objects.isNull(startTime) || Objects.isNull(endTime)) {
            return null;
        }
        Duration duration = Duration.between(startTime, endTime);
        long time = duration.get(ChronoUnit.SECONDS) * 1000 + duration.get(ChronoUnit.NANOS)/1000000;
        String strHour = "" + (time/(3600 * 1000));
        String strMinute = "" + time%(3600 * 1000)/(60 * 1000);
        String strSecond = "" + time%(3600 * 1000)%(60 * 1000)/1000;
        String strMicroSecond = "" + time%(3600 * 1000)%(60 * 1000)%1000%1000;

        strHour = strHour.length() < 2? "0" + strHour: strHour;
        strMinute = strMinute.length() < 2? "0" + strMinute: strMinute;
        strSecond = strSecond.length() < 2? "0" + strSecond: strSecond;

        String strRsult = "";

        if (!strHour.equals("00"))
        {
            strRsult += strHour + "时";
        }
        if (!strMinute.equals("00"))
        {
            strRsult += strMinute + "分";
        }
        if(!strSecond.equals("00")) {
            strRsult += strSecond + "秒";
        }
        strRsult += strMicroSecond + "毫秒";
        return strRsult;
    }


    /**
     * 计算时间段<b>时分秒</b> 格式
     */
    public static String toDurationTimeStr(String startTime, String endTime) {
        if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
            return null;
        }
        return toDurationTimeStr(parseStdLongTimeStr(startTime), parseStdLongTimeStr(endTime));
    }

    public static Date parseStdLongTime(String text) {
        Date date = null;
        if (StringUtils.isNotBlank(text)) {
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = LocalDateTime.parse(text, STD_LONG_TIME_FMT).atZone(zoneId);
            date = Date.from(zdt.toInstant());
        }

        return date;
    }

    public static Date parseStdShortTime(String text) {
        Date date = null;
        if (!Strings.isNullOrEmpty(text)) {
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = LocalDate.parse(text, STD_DATE_FMT).atStartOfDay().atZone(zoneId);
            date = Date.from(zdt.toInstant());
        }

        return date;
    }
}
